#pragma once
#include <iostream>
#include <vector>
#include <pthread.h>
#include "Sem.hpp"
#include "Mutex.hpp"

namespace RingBufferModule
{
    using namespace SemMoudle;
    using namespace LockModule;
    template <typename T>
    class RingBuffer
    {
    public:
        RingBuffer(int size)
            : _ring(size), // 给vector初始化一个大小
              _size(size),
              _tail(0),       // 生产者的默认位置
              _head(0),       // 消费者的默认位置
              _datasem(0),    // 默认数据为0
              _spacesem(size) // 默认空间为满
        {
        }
        // 生产者
        void Equeue(const T &in)
        {
            _spacesem.P(); // 预定一个空间

            {
                // 上锁
                LockGuard lockguard(_p_lock);
                // pthread_mutex_lock(&_p_lock);
                _ring[_tail] = in; // 生产
                _tail++;
                _tail %= _size; // 维持环形特性
                // pthread_mutex_unlock(&_p_lock);
            }

            _datasem.V(); // 释放一个数据
        }
        // 消费者
        void Pop(T *out)
        {
            _datasem.P(); // 预定一个数据

            {
                LockGuard lockguard(_c_lock);
                // pthread_mutex_lock(&_c_lock);
                *out = _ring[_head]; // 取出数据
                _head++;
                _head %= _size;
                // pthread_mutex_unlock(&_c_lock);
            }

            _spacesem.V(); // 释放一个空间
        }
        ~RingBuffer()
        {
        }

    private:
        std::vector<T> _ring; // 环， 临界资源
        int _size;            // 总容量
        int _tail;            // 生产者位置
        int _head;            // 消费位置

        Sem _datasem;  // 数据信号量
        Sem _spacesem; // 空间信号量
        Mutex _p_lock; // 生产者锁
        Mutex _c_lock; // 消费者锁
    };
}